package cn.flying.base.sys.configuration.shiro;

import javax.servlet.Filter;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

/**
 * @description: Shiro相关配置
 * @author: lvyong
 * @date: 2022年05月22日 07:51
 * @version: 1.0
 */
@Configuration
public class ShiroConfiguration {

    /**
     * 全局session超时时间
     */
    @Value("${global-session-timeout:30}")
    private Integer timeOut;

    /**
     * 自定义cookie名称
     *
     * @return
     */
    @Bean
    public SimpleCookie sessionIdCookie() {
        SimpleCookie cookie = new SimpleCookie("X-Token");
        cookie.setHttpOnly(true);
        return cookie;
    }

    /**
     * 全局session管理
     *
     * @return
     */
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        //自定义cookie 中sessionId 的key
        sessionManager.setSessionIdCookie(sessionIdCookie());
        sessionManager.setSessionIdCookieEnabled(true);
        //使用redis 来持久化session 信息
//        sessionManager.setSessionDAO(redisSessionDAO());
        //删除过期session
        sessionManager.setDeleteInvalidSessions(true);
        //设置session 过期时间 毫秒值
        sessionManager.setGlobalSessionTimeout(timeOut * 60 * 1000);
        //开启session过期校验
        sessionManager.setSessionValidationSchedulerEnabled(true);
        return sessionManager;
    }

    /**
     * 过滤器配置
     *
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager());

        ShiroLoginFilter shiroLoginFilter = new ShiroLoginFilter();
        Map<String, Filter> filters = new HashMap<>();
        filters.put("authc", shiroLoginFilter);
        shiroFilterFactoryBean.setFilters(filters);

        /**
         * anon: 无需认证就可以访问
         * authc： 需要认证才能够访问
         */
        //设置未认证(登录)时，访问需要认证的资源时跳转的页面
        shiroFilterFactoryBean.setLoginUrl("/login");

        // 登录成功后跳转的url
//        shiroFilterFactoryBean.setSuccessUrl("/userList");

        //设置访问无权限的资源时跳转的页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/login");

        //指定路径和过滤器的对应关系
        Map<String, String> filterMap = new LinkedHashMap<>();

        // 定义filterChain，静态资源不拦截
        // 配置不会被拦截的链接 顺序判断  相关静态资源
        filterMap.put("/static/**", "anon");
        filterMap.put("/css/**", "anon");
        filterMap.put("/font/**", "anon");
        filterMap.put("/images/**", "anon");
        filterMap.put("/js/**", "anon");
        filterMap.put("/layui/**", "anon");
        filterMap.put("/lib/**", "anon");
        filterMap.put("/style/**", "anon");
        filterMap.put("/ztree/**", "anon");
        filterMap.put("/modules/**", "anon");
        filterMap.put("/config.js", "anon");

        filterMap.put("/captcha", "anon");
        filterMap.put("/forget", "anon");
        filterMap.put("/register", "anon");
        filterMap.put("/login/**", "anon");
        filterMap.put("/doLogin/**", "anon");

        // druid数据源监控页面不拦截
        filterMap.put("/druid/**", "anon");
        // 配置退出过滤器，其中具体的退出代码Shiro已经替我们实现了
        filterMap.put("/logout", "logout");

        //其他路径则需要登录才能访问
        filterMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 安全管理器配置
     *
     * @return
     */
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager() {
        // 配置SecurityManager，
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        // 注入shiroRealm
        defaultWebSecurityManager.setRealm(shiroRealm());
        //session
        defaultWebSecurityManager.setSessionManager(sessionManager());
        return defaultWebSecurityManager;
    }

    /**
     * 认证/授权
     *
     * @return
     */
    @Bean
    public Realm shiroRealm() {
        ShiroRealm realm = new ShiroRealm();
        //使用HashedCredentialsMatcher带加密的匹配器来替换原先明文密码匹配器
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //指定加密算法
        hashedCredentialsMatcher.setHashAlgorithmName("SHA-256");
        //指定加密次数
        hashedCredentialsMatcher.setHashIterations(1024);
        // 生成16进制, 与注册时的生成格式相同
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);

        realm.setCredentialsMatcher(hashedCredentialsMatcher);

        //开启缓存管理
        //默认缓存
        realm.setCacheManager(new EhCacheManager());

        //开启全局缓存
        realm.setCachingEnabled(true);
        //开启认证缓存
        realm.setAuthenticationCachingEnabled(true);
        realm.setAuthenticationCacheName("authenticationCache");
        //开启权限缓存
        realm.setAuthorizationCachingEnabled(true);
        realm.setAuthorizationCacheName("authorizationCache");
        return realm;
    }

    /**
     * 解决shiro导致aop失效，将该方法设置为静态
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        //这一句比较重要
        creator.setProxyTargetClass(true);
        return creator;
    }
}
